package main

import (
	"bytes"
	"encoding/binary"
	"golang.org/x/net/ipv4"
	"log"
	"net"
	"syscall"
)

const UDP_HEADER_LEN = 8

type UdpHeader struct {
	SourcePort      uint16
	DestinationPort uint16
	Length          uint16
	Checksum        uint16
}

func main() {

	var err error
	destIP := net.ParseIP("172.16.21.19")
	srcIP := net.ParseIP("1.2.3.4")
	proto := 17
	data := []byte("TESTING-ONE-TWO-THREE")

	udpHeader_t := UdpHeader{
		// SourcePort:      8887,
		// DestinationPort: 8888,
		// Length:          uint16(UDP_HEADER_LEN + len(data)),
	}

	buf := bytes.NewBuffer([]byte{})
	err = binary.Write(buf, binary.BigEndian, &udpHeader_t)
	if err != nil {
		log.Fatal(err)
	}

	udpHeader := buf.Bytes()
	dataWithHeader := append(udpHeader, data...)

	h := &ipv4.Header{
		Version:  ipv4.Version,
		Len:      ipv4.HeaderLen,
		TotalLen: ipv4.HeaderLen + UDP_HEADER_LEN + len(data),
		ID:       12345,
		Protocol: proto,
		Dst:      destIP.To4(),
		Src:      srcIP.To4(),
	}

	fd, err := syscall.Socket(syscall.AF_INET, syscall.SOCK_RAW, syscall.IPPROTO_RAW)
	if err != nil {
		log.Fatal(err)
	}

	err = syscall.SetsockoptInt(fd, syscall.IPPROTO_IP, syscall.IP_HDRINCL, 1)
	if err != nil {
		log.Fatal(err)
	}

	addr := syscall.SockaddrInet4{
		Addr: [4]byte{172, 16, 21, 19},
	}

	out, err := h.Marshal()
	if err != nil {
		log.Fatal(err)
	}

	packet := append(out, dataWithHeader...)
	err = syscall.Sendto(fd, packet, 0, &addr)
	if err != nil {
		log.Fatal("Sendto:", err)
	}

	syscall.Close(fd)

}